JavaScript
中的call()
和apply()
都是用于调用当前函数functionObject
,并可同时使用指定对象thisObj
作为本次执行时functionObject
函数内部的this
指针引用。它们都输属于
Function
对象,所有主流浏览器均支持。
1. call()和apply()的定义
1.1 call()方法
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
语法:functionObject.call( [ thisObj [, arg1 [, arg2 [, args...]]]] )
参数:
参数 | 描述 |
---|---|
thisObj |
可选/Object类型 ,指定执行functionObject 函数时,函数内部this 指针引用的对象。 |
arg1 |
可选/任意类型 ,调用functionObject 函数时传入的第1个参数。 |
arg2 |
可选/任意类型 ,调用functionObject 函数时传入的第2个参数。 |
args |
可选/任意类型 ,调用functionObject 函数时传入的更多参数,可以有多个。 |
1.2 apply()方法
定义:应用一个对象的一个方法,用另一个对象替换当前对象。
语法:functionObject.apply( [ thisObj [, argsArray ]] )
参数:
参数 | 描述 |
---|---|
thisObj |
可选/Object类型 ,指定执行functionObject 函数时,函数内部this 指针引用的对象。 |
argsArray |
可选/Array或arguments 对象,调用functionObject 时传入的参数数组或arguments对象。 |
1.3 call()和apply()的异同
相同点:
都可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj
指定的新对象。
不同点:
call()
:则是直接的参数列表,主要用在js
对象各方法互相调用的时候,使当前this
实例指针保持一致,或在特殊情况下需要改变this
指针。如果没有提供thisObj
参数,那么Global
对象被用作thisObj
。apply()
:最多只能有两个参数———新this
对象和一个数组argsArray
。如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里面。如果 argArray 不是一个有效的数组或者不是arguments
对象,那么将导致一个TypeError
。如果没有提供argsArray
和thisObj
任何一个参数,那么Global
对象将被用作thisObj
,并且无法被传递任何参数。
总结:
call()
和apply()
都可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj
指定的新对象。call()
函数是将FunctionObject
的参数一个个分别传入,如functionObject.call(thisObj,arg1,arg2,arg3)
;apply()
函数是将FunctionObject
对象的参数以一个数组或arguments
对象的形式整体传入,如functionObject.apply(func1,[arg1,arg2,arg3])
。
2. call()和apply()实例
2.1 实例一
|
|
说明:
例子中用add
来替换sub
,add.call(sub,3,1) == add(3,1)
,所以运行结果为:4
;
需要注意的是,这里直接用了函数名sub
,而不是sub()
,因为在js
中的函数其实是对象,函数名是对Function
对象的引用。
2.1 实例二
|
|
说明
通过call
或apply
方法,将原本属于Animal
对象的showName()
方法交给对象cat
来使用了。因此输入结果为"Cat"
。
2.3 实例三(实现继承)
|
|
说明:
Animal.call(this, name)
的意思就是使用 Animal
对象代替this
对象,那么Cat
对象就能够直接调用Animal
的方法以及属性了。
2.4 实例四(多重继承)
|
|
3. apply()的其他妙用
既然apply和call的用法差不多,那么为什么还同时存在呢?
——这是因为apply所传的参数类型(数组)还有其他妙用。
3.1 Math.max可以实现得到数组中最大的一项
因为Math.max
参数不支持数组传递,但是它支持列表传递,即Math.max(param1,param2,param3…)
,所以可以根据apply
的特点来解决 var max=Math.max.apply(null,array)
,这样轻易的可以得到一个数组中最大的一项。(apply
会将一个数组转换为一个参数接一个参数的传递给方法)。
注意:调用的时候第一个参数给了一个null
,是因为没有对象去调用这个方法,只需要用这个方法帮助运算,得到返回的结果就行,所以直接传递了一个null
过去。
3.2 Array.min 可以实现得到数组中最小的一项
同样和max
是一个思想 var min=Math.min.apply(null,array)
。
3.3 Array.prototype.push 可以实现两个数组合并
同样push
方法没有提供push
一个数组,但是它提供了push(param1,param,…paramN)
所以同样也可以通过apply
来转换一下这个数组,即:
|
|
也可以这样理解,arr1
调用了push
方法,参数是通过apply
将数组装换为参数列表的集合。
总结:
当目标函数只需要n
个参数列表,而不接收一个数组的形式([param1[,param2[,…[,paramN]]]])
,可以通过apply
的方式巧妙地解决这个问题。